local tabletool = require "tabletool"
local timetool = require "timetool"
local msghelper = require "tablehelper"
local timer = require "timer"
local filelog = require "filelog"
local cardtool = require "cardtool"
local skynet = require "skynet"
local redisdao = require "redisdao"
local configdao = require "configdao"
local cluster = require "skynet.cluster"
local json = require "cjson"
json.encode_sparse_array(true,1,1)
local queue = require "skynet.queue"
local cs = queue()
local math_floor = math.floor
local math_ceil = math.ceil

require "pszenum"
local gamelogic		-- = require "gamelogic"
local seatlogic		-- = require "seatlogic"
local TableLogic = {}


--------------------

---获取节点配置
--包括服务费配置，奖池配置
--nodeconf = {tipconf,jackoptconf}
--
local function getnodeconf()
	local nodeconf = nil
	local result, data = redisdao.query_data(".gmmqredis", "get", "psznode_conf")
    if result and data then
        nodeconf = json.decode(data)
    end
    return nodeconf or {}
end

local function check_cangetjack(card_type)
	local canget = false
	local nodeconf = getnodeconf()
    local jackoptconf = nodeconf.tipconf
	if not jackoptconf or not jackoptconf.getjackopt then return canget end
	for cardtype, get_per in pairs(jackoptconf.getjackopt) do
		if tonumber(cardtype) == card_type then canget = true break end
	end
	return canget
end

-----------------------------------

function TableLogic.init(tablebase, conf)
	local table_data = tablebase.table_data
	gamelogic = tablebase.logic.gamelogic
	seatlogic = tablebase.logic.seatlogic
	if conf == nil then
		filelog.sys_error("TableLogic.init conf = nil")
		return false
	end
	table_data.idx = conf.idx
	table_data.state = ETableState.TABLE_STATE_WAIT_MIN_PLAYER

	local seat
	local count = 1
    while count <= conf.max_player_num do
    	seat = {
			index = 0,
			rid = 0,
			state = 0,  --改坐位玩家状态
			playerinfo = {
				rolename = "",
				logo = "",
				sex = 0,
				ip_addr = "",
				fangka = 0,
				diamond = 0,
			},
			is_tuoguan = 0,
    		diamond_base = 0,  --携带进桌的金币的备份
    		--Add 座位其他变量
    		timeout_count = 0, --超时次数
    		diamond = 0,       --玩家携带进桌的金币
    		getdiamond = 0,		--当前局获得金币
    		cards = {}, 	--所持有的牌
    		ready_timer_id = -1, --准备倒计时定时器
    		ready_to_time = 0, --准备到期时间
    		is_ready = EBOOL.FALSE, 	--是否准备
    		timeout_fold = 0,	--超时弃牌次数
    	}
    	seatlogic.init(seat, count)
    	table.insert(table_data.seats, seat)
    	table_data.robotdata.seats[seat.index] = {}
		count = count + 1
    end
	table_data.conf = tabletool.deepcopy(conf)
	table_data.the_round = 1   --当前游戏轮数
	table_data.makers = 0   --庄家
	table_data.playernum = 0 --玩家数量

	gamelogic.init(tablebase)

     ----获取最新彩池信息
     table_data.jackopt_info = {}
    --  if table_data.conf.room_type == ERoomType.ROOM_TYPE_DIAMOND and table_data.conf.base_score > 10 then
    --     TableLogic.register_jackopt(table_data)
    --     TableLogic.get_jackoptinfo(table_data)
    --  end
    --  table_data.tip = TableLogic.get_tip(table_data)
    --  table_data.jacktip = TableLogic.get_jacktip(table_data)

	return true
end

function TableLogic.checkallonline(table_data)
	local online = false
	for _, seat in ipairs(table_data.seats) do
		if seat.state ~= ESeatState.SEAT_STATE_NO_PLAYER then
			if not seat.is_disconnect then
				online = true
				break
			end
		end
	end
	if not online then
		if table_data.timer_id > 0 then
			timer.cleartimer(table_data.timer_id)
			table_data.timer_id = -1
		end
		for _, seat in ipairs(table_data.seats) do
			if seat.state ~= ESeatState.SEAT_STATE_NO_PLAYER then
				TableLogic.passive_standuptable(table_data, seat)
			end
		end
	end
	return online
end

function TableLogic.disconnect(table_data, request, seat)
	if not table_data.match_type and (seat.state == ESeatState.SEAT_STATE_WAIT_READY or seat.state == ESeatState.SEAT_STATE_WATCHING) then
		TableLogic.passive_standuptable(table_data, seat)
	else
		if table_data.playernum == 1 then
			TableLogic.passive_standuptable(table_data, seat)
		else
			seat.is_tuoguan = EBOOL.TRUE
			seat.is_disconnect = true
			-- if TableLogic.checkallonline(table_data) then
				msghelper:sendmsg_to_alltableplayer("disconnectN", {
					rid = seat.rid,
					seat_index = seat.index,
					is_tuoguan = seat.is_tuoguan,
				})
			-- end
		end
	end
end

function TableLogic.clear(table_data)
	if table_data.timer_id > 0 then
		timer.cleartimer(table_data.timer_id)
		table_data.timer_id = -1
	end

	if table_data.delete_table_timer_id > 0 then
		timer.cleartimer(table_data.delete_table_timer_id)
		table_data.delete_table_timer_id = -1
	end

	for k,v in pairs(table_data) do
		table_data[k] = nil
	end
end

function TableLogic.leaveallplayers(table_data)
	local playernum = 0
	for _, seat in ipairs(table_data.seats) do
		if seat.state ~= ESeatState.SEAT_STATE_NO_PLAYER then
			TableLogic.passive_standuptable(table_data, seat)
			playernum = playernum + 1
		end
	end
	if playernum == 0 then
		local delete_table_timer_id = timer.settimer(0, "delete_table")
		table_data.delete_table_timer_id = delete_table_timer_id
	end
end

--[[
	seat: nil表示否， 非nil表示是
--]]
function TableLogic.entertable(table_data, request, seat)
	if seat and seat.is_tuoguan == EBOOL.TRUE then
		seat.is_tuoguan = EBOOL.FALSE
	end
	if table_data.conf.room_type ~= ERoomType.ROOM_TYPE_ZJ_FRIEND then
		if table_data.delete_table_timer_id and table_data.delete_table_timer_id > 0 then
			timer.cleartimer(table_data.delete_table_timer_id)
			table_data.delete_table_timer_id = -1
		end
	end
	if table_data.conf.match_type then
		table_data.standing[request.rid] = {request.rid, 1}
	else
		table_data.standing[request.rid] = {request.rid}
	end
end

function TableLogic.reentertable(table_data, request, seat)
	if table_data.standing[request.rid] then
		table_data.standing[request.rid][2] = nil
	end
	msghelper:sendmsg_to_alltableplayer("disconnectN", {
		rid = seat.rid,
		seat_index = seat.index,
		is_tuoguan = EBOOL.FALSE,
	})
	---------------游戏进行中---------------
	if not TableLogic.is_onegameend(table_data) then --游戏没结束
		--把牌发给玩家
		seatlogic.dealcards(seat)
		if table_data.seat_index == seat.index then
			--通知玩家当前该他操作
			local doactionntcmsg = {
				rid = table_data.seats[table_data.seat_index].rid,
				seat_index = table_data.seat_index,
				action_to_time = table_data.action_to_time,
				game_turns = table_data.turns,
			}
			msghelper:sendmsg_to_tableplayer(seat, "todoN", doactionntcmsg)
		end
	end

	-----------------游戏结束------------------
	if table_data.state == ETableState.TABLE_STATE_GAME_END then --游戏结束 
		if seat.state == ESeatState.SEAT_STATE_WAIT_READY or seat.state == ESeatState.SEAT_STATE_COMPARE_FAIL or seat.state == ESeatState.SEAT_STATE_FOLD then
			seatlogic.dealcards(seat)
		end
	end
	if table_data.delete_table_timer_id and table_data.delete_table_timer_id > 0 then
		timer.cleartimer(table_data.delete_table_timer_id)
		table_data.delete_table_timer_id = -1
	end
end

function TableLogic.sitdowntable(table_data, request, seat)
	if table_data.conf.match_type then
		seat.waitreenter = 1
	end

	seat.state = ESeatState.SEAT_STATE_WAIT_READY	--等待开始
	seat.rid = request.rid
	seat.playerinfo.level = request.playerinfo.level
	seat.playerinfo.rolename = request.playerinfo.rolename
	seat.playerinfo.logo = request.playerinfo.logo
	seat.playerinfo.sex = request.playerinfo.sex
	seat.playerinfo.ip_addr = request.playerinfo.ip_addr or ''
	seat.playerinfo.gps_addr = request.playerinfo.gps_addr or ''
	seat.playerinfo.fangka = request.money.fangka or 0
	seat.playerinfo.diamond = request.money.diamond or 0
	seat.playerinfo.coin = request.money.coin or 0
	seat.playerinfo.introduce = request.playerinfo.intro or ''
	seat.playerinfo.upvoted_num = request.playerinfo.upvoted_num or 0
	seat.playerinfo.downvoted_num = request.playerinfo.downvoted_num or 0
	seat.playerinfo.logoframe = request.playerinfo.logoframe
	seat.diamond = request.money.diamond
	seat.getdiamond = seat.diamond
	seat.diamond_base = seat.diamond
	if table_data.conf.room_type == ERoomType.ROOM_TYPE_ZJ_FRIEND then
		seat.diamond = 0
		seat.getdiamond = 0
		seat.diamond_base = seat.diamond
	elseif table_data.conf.room_type == ERoomType.ROOM_TYPE_COIN then
		seat.diamond = request.money.coin
		seat.getdiamond = request.money.coin
		seat.diamond_base = seat.diamond
	end

	-- 判读sitdown时，玩家是否处于中途进入
	if table_data.gaming then
		seat.state = ESeatState.SEAT_STATE_WATCHING
	end
	
	table_data.standing[request.rid] = nil

	if not table_data.conf.match_type or table_data.the_round > 1 then
		local noticemsg = {
			rid = seat.rid,
			seat = {},
			player_info = {},
		}
		msghelper:copy_seatinfo(noticemsg.seat, seat)
		msghelper:copy_playerinfo(noticemsg.player_info, seat)
		msghelper:sendmsg_to_alltableplayer("sitdowntableN", noticemsg)

		local outoftimermsg = {
			rid = seat.rid,
			seat_index = seat.index,
		}
		if not table_data.gaming then
			-- seat.ready_timer_id = timer.settimer(table_data.conf.ready_timeout*100, "doready", outoftimermsg)
			-- seat.ready_to_time = timetool.get_time() + table_data.conf.ready_timeout
			-- local doreadyntcmsg = {
			-- 	rid = seat.rid,
			-- 	seat_index = seat.index,
			-- 	ready_to_time = timetool.get_time() + table_data.conf.ready_timeout,
			-- 	is_ready = EBOOL.FALSE,
			-- }
			-- msghelper:sendmsg_to_alltableplayer("doreadyN", doreadyntcmsg)
			seat.ready_timer_id = timer.settimer(60, "doreadydelay", outoftimermsg)
		end
	end

	if seat.is_tuoguan == EBOOL.TRUE then
		seat.is_tuoguan = EBOOL.FALSE
		--TO ADD 添加托管处理
	end
	--增加桌子人数计数 
	table_data.sitdown_player_num = table_data.sitdown_player_num + 1
	table_data.playernum = table_data.playernum + 1
	gamelogic.onsitdowntable(seat)
	if table_data.conf.room_type == ERoomType.ROOM_TYPE_DIAMOND then
		local data = {
			cur_player = table_data.sitdown_player_num,
			is_public = table_data.conf.is_public,
			mtype = table_data.conf.match_type,
			rtype = table_data.conf.room_type,
			count = 1,
			rid = seat.rid,
			logo = seat.playerinfo.logo,
		}
		msghelper:sendmsg_to_roomsvr("update_table_player", table_data.conf.idx, data)
	end

	-------------------------- robot --------------------------
	-- 现在机器人作为陪打， 陪打作为和玩家游戏的机器人
	-- if request.playerinfo.level == 99 then
	if request.playerinfo.is_test then
		seat.isrobot = true
		seat.entercarry = seat.diamond
		msghelper:sendmsg_to_roomsvr("change_robot_num", 1, table_data.conf.idx, table_data.conf.is_public, table_data.conf.match_type, table_data.conf.room_type)
		if table_data.sitdown_player_num == 1 and table_data.conf.create_user_rid == 101 then
			table_data.conf.name = seat.playerinfo.rolename .. "的房间"
	    	table_data.conf.rid = seat.rid
	    	table_data.conf.create_user_rid = rid
			table_data.conf.create_user_name = seat.playerinfo.rolename
	    	table_data.conf.create_user_logo = seat.playerinfo.logo
		end
	else
		-------------------------- test robot --------------------------
		-- if request.playerinfo.is_test then
		if request.playerinfo.level == 99 then
			seat.entercarry = seat.diamond
			seat.istest = true
		end
	end
end

function TableLogic.gameready(table_data, request, seat)
	if seat.ready_timer_id and seat.ready_timer_id > 0  then --取消准备倒计时
		timer.cleartimer(seat.ready_timer_id)
		seat.ready_timer_id = -1
		seat.ready_to_time = 0
	end
	if table_data.conf.match_type then -- and table_data.the_round > 1 then
		if table_data.playernum < 2 then
			local match_type = table_data.conf.match_type
			if table_data.conf.room_type == ERoomType.ROOM_TYPE_DIAMOND then
				skynet.call(".router","lua", "restart_matchtable", {request.rid}, match_type)
			elseif table_data.conf.room_type == ERoomType.ROOM_TYPE_COIN then
				skynet.call(".router","lua", "restart_coinmatchtable", {request.rid}, match_type)
			end
			TableLogic.passive_standuptable(table_data, seat)
			return
		end
	end

	seat.state = ESeatState.SEAT_STATE_WAIT_START
	seat.is_ready = EBOOL.TRUE
	
	if not table_data.conf.match_type or table_data.the_round > 1 then
		--[[
		if table_data.conf.room_type == ERoomType.ROOM_TYPE_DIAMOND then
			if not seat.isrobot then	-- 每次准备同步agent数据
				seat.playerinfo.fangka = request.money.fangka or 0
				seat.playerinfo.diamond = request.money.diamond or 0
				seat.playerinfo.coin = request.money.coin or 0
				seat.diamond = request.money.diamond
				seat.getdiamond = seat.diamond
				seat.diamond_base = seat.diamond
				msghelper:sendmsg_to_alltableplayer("moneychangeN", {
					money_change_list = {
						{
							rid = seat.rid,
							money_type = 2,
							value = seat.diamond,
						},
					}
				})
			end
		elseif table_data.conf.room_type == ERoomType.ROOM_TYPE_COIN then	-- 每次准备同步agent数据
			seat.playerinfo.fangka = request.money.fangka or 0
			seat.playerinfo.diamond = request.money.diamond or 0
			seat.playerinfo.coin = request.money.coin or 0
			seat.diamond = request.money.coin
			seat.getdiamond = seat.diamond
			seat.diamond_base = seat.diamond
			msghelper:sendmsg_to_alltableplayer("moneychangeN", {
				money_change_list = {
					{
						rid = seat.rid,
						money_type = 3,
						value = seat.diamond,
					},
				}
			})
		end
		--]]
		local noticemsg = {
			rid = seat.rid,
			seat_index = seat.index,
			state = seat.state,
			is_ready = EBOOL.TRUE,
			table_state = table_data.state,
		}
		msghelper:sendmsg_to_alltableplayer("gamereadyN", noticemsg)
	end
	
	if not table_data.gaming then
		TableLogic.startgame(table_data)
	end
end

function TableLogic.startgame(table_data, request, handle)
	if handle then
		table_data.enterclose = true
	end
	if TableLogic.is_canstartgame(table_data) then
		table_data.state = ETableState.TABLE_STATE_GAME_START
		table_data.gaming = true
		if table_data.conf.room_type == ERoomType.ROOM_TYPE_ZJ_FRIEND then
			table_data.cur_games_times = table_data.cur_games_times + 1
		elseif table_data.conf.room_type == ERoomType.ROOM_TYPE_ZJ_DIAMOND then
			table_data.cur_games_times = table_data.cur_games_times + 1
		end
		gamelogic.gamestart()
		-- filelog.warn("------ game start ------")
		return true
	else
		table_data.enterclose = nil
	end
	return false
end

--
--处理重新匹配
--
function TableLogic.restart_matchtable(table_data, rid)
	local rids = {}
	local ts = timetool.get_time()
	for k, v in ipairs(table_data.seats) do
		if v.rid ~= (rid or 0) and v.state == ESeatState.SEAT_STATE_WAIT_START then
			if not v.ready_to_time or (v.ready_to_time == 0) or ts <= (v.ready_to_time - 1) then
				table.insert(rids, v.rid)
			end
		end
	end
	local match_type = table_data.conf.match_type
	if table_data.conf.room_type == ERoomType.ROOM_TYPE_DIAMOND then
		msghelper:callmsg_to_roomsvr("restart_matchtable", rids, match_type)
	elseif table_data.conf.room_type == ERoomType.ROOM_TYPE_COIN then
		msghelper:callmsg_to_roomsvr("restart_coinmatchtable", rids, match_type)
	end
	for _, rid in ipairs(rids) do
		local seat = TableLogic.get_seat_by_rid(table_data, rid)
		TableLogic.passive_standuptable(table_data, seat, nil, true)
	end
end

function TableLogic.leavetable(table_data, request, isrobot, re)
	local delete = false
	if request.rid then
		local leavetablentc = {rid = request.rid}
		msghelper:sendmsg_to_alltableplayer("leavetableN", leavetablentc)
		msghelper:sendmsg_to_roomsvr("playerleavetable", request.rid, table_data.conf.game_room_type, isrobot)
		if isrobot then
			if isrobot == 2 then
				pcall(cluster.send, "robotnode", ".router", "request_robot_leave", "psznode", table_data.idx, {request.rid})
			elseif isrobot == 1 then
				msghelper:sendmsg_to_roomsvr("delete_robot", request.rid)
			end
		end
	end

	if not table_data.conf.match_type then
		local isallrobot = true
		for _, seat in ipairs(table_data.seats) do
			if seat.state ~= ESeatState.SEAT_STATE_NO_PLAYER then
				if seat.rid ~= request.rid and not seat.isrobot then
					isallrobot = false
				end
			end
		end
		if isallrobot then
			if TableLogic.is_onegameend(table_data) then	-- 游戏没结束
				delete = true
			end
		end
	end

	if table_data.conf.match_type and table_data.playernum < 2 then	-- 匹配桌人数太少，退桌重新进匹配
		if TableLogic.is_onegameend(table_data) then	-- 游戏没结束不能进行重连
			--匹配场
			if not table_data.recycled and not re then
				table_data.recycled = true
				TableLogic.restart_matchtable(table_data, request.rid) --匹配场，将座位上玩家，加入匹配队列
			end
		end
	end

	local retain_time = table_data.conf.retain_time
	if table_data.playernum <= 0 then
		if not table_data.delete_table_timer_id or table_data.delete_table_timer_id == -1 then
			delete = true
		else
			delete = false
		end
	end

	if table_data.conf.room_type == ERoomType.ROOM_TYPE_ZJ_FRIEND then
		if request.rid == table_data.conf.create_user_rid then
			delete = true
			local noteresultntcmsg = {
				table_index = table_data.conf.idx,
				is_success = true,
			}
			msghelper:sendmsg_to_alltableplayer("disbandresultN", noteresultntcmsg)
		end
	elseif table_data.conf.room_type == ERoomType.ROOM_TYPE_ZJ_DIAMOND then
		if table_data.cur_games_times < table_data.conf.game_times then
			retain_time = 10 * 60
		end
	end

	if delete then
		table_data.delete_table_timer_id = timer.settimer(retain_time*100, "delete_table")
		table_data.the_round = 1
		table_data.recycled = nil
		if table_data.timer_id and table_data.timer_id > 0 then
			timer.cleartimer(table_data.timer_id)
			table_data.timer_id = -1
		end
		for k,v in ipairs(table_data.seats or {}) do
			if v.state == ESeatState.SEAT_STATE_WAIT_READY then
				if v.ready_timer_id > 0 then
					timer.cleartimer(v.ready_timer_id)
					v.ready_timer_id = -1
				end
			end
		end
	end
	if table_data.standing then
		table_data.standing[request.rid] = nil
	end

	--[[
	if table_data.conf.match_type then
		if table_data.playernum >= 2 and table_data.playernum < table_data.conf.max_player_num then
			if table_data.conf.room_type == ERoomType.ROOM_TYPE_DIAMOND then
				for i = 1, table_data.conf.max_player_num - table_data.playernum do
					msghelper:sendmsg_to_roomsvr("add_waiting_player", table_data.conf.idx, table_data.conf.match_type)
					filelog.warn("------ leave table make add_waiting_player ------")
				end
			elseif table_data.conf.room_type == ERoomType.ROOM_TYPE_COIN then
				for i = 1, table_data.conf.max_player_num - table_data.playernum do
					msghelper:sendmsg_to_roomsvr("add_waiting_player_coin", table_data.conf.idx, table_data.conf.match_type)
					filelog.warn("------ leave table make add_waiting_player_coin ------")
				end
			end
		end
	end
	--]]
end

function TableLogic.passive_standuptable(table_data, seat, reason, re)
	local rid, isrobot
	if seat then
		rid = seat.rid
		if seat.state == ESeatState.SEAT_STATE_COMPARE_FAIL or seat.state == ESeatState.SEAT_STATE_FOLD then
			if table_data.conf.room_type == ERoomType.ROOM_TYPE_DIAMOND
			or table_data.conf.room_type == ERoomType.ROOM_TYPE_COIN
			or table_data.conf.room_type == ERoomType.ROOM_TYPE_ZJ_DIAMOND then
				TableLogic.game_leave_noend(table_data, rid)
			end
		end

		if not TableLogic.is_onegameend(table_data) then --一局游戏结束，is_onegameeend返回ture
			local action = timetool.get_time() .. "_"
				.. rid .. "_"
				.. '-2' .. "_"
				.. '0' .. "_"
				.. (table_data.all_bets or '0') .. "_"
				.. '0'
			TableLogic.save_actions(table_data, action)

			if gamelogic.is_ingame(seat) == true then
				if seat.state ~= ESeatState.SEAT_STATE_WATCHING
					and seat.state ~= ESeatState.SEAT_STATE_COMPARE_FAIL
					and seat.state ~= ESeatState.SEAT_STATE_FOLD then
					gamelogic.onstanduptable(seat)
				end
				if seat.state ~= ESeatState.SEAT_STATE_WATCHING then
					local losecoin, losediamond = 0, 0
					if table_data.conf.room_type == ERoomType.ROOM_TYPE_DIAMOND or table_data.conf.room_type == ERoomType.ROOM_TYPE_ZJ_DIAMOND then
						losecoin = 0
						losediamond = seat.diamond - seat.diamond_base
					elseif table_data.conf.room_type == ERoomType.ROOM_TYPE_COIN then
						losecoin = table_data.tmpdiamond.coin[rid]
						if table_data.tmpdiamond.diamond and table_data.tmpdiamond.diamond[rid] then
							losediamond = table_data.tmpdiamond.diamond[rid].value
						end
					end

					table_data.leaves = table_data.leaves or {}
					table_data.leaves[seat.index] = {
						rid = rid,
						seat_index = seat.index,
						rolename = seat.playerinfo.rolename,
						logo = seat.playerinfo.logo,
						lose_money = seat.diamond - seat.diamond_base,
						lose_diamond = losediamond,
						lose_coin = losecoin,
						card_type = cardtool.getCardType(seat.cards) or -1,
						cards = tabletool.deepcopy(seat.cards),
					}
				end
			end
		end
		table_data.sitdown_player_num = table_data.sitdown_player_num - 1
		table_data.playernum = table_data.playernum - 1
		if table_data.conf.room_type == ERoomType.ROOM_TYPE_DIAMOND then
			local data = {
				cur_player = table_data.sitdown_player_num,
				is_public = table_data.conf.is_public,
				mtype = table_data.conf.match_type,
				rtype = table_data.conf.room_type,
				count = -1,
				rid = seat.rid,
				logo = nil,
			}
			msghelper:sendmsg_to_roomsvr("update_table_player", table_data.conf.idx, data)
		end

		local noticemsg = {
			rid = rid, 
			seat_index = seat.index,
			state = seat.state,
			reason = reason,
		}
		msghelper:sendmsg_to_alltableplayer("standuptableN", noticemsg) --同知座位上的人，某位玩家离
		if seat.index == table_data.winer_index then
			table_data.winer_index = nil
		end
		--初始化座位数据
		isrobot = seat.isrobot and 1 or (seat.istest and 2 or nil)
		if isrobot == 1 then
			msghelper:sendmsg_to_roomsvr("change_robot_num", -1, table_data.conf.idx, table_data.conf.is_public, table_data.conf.match_type, table_data.conf.room_type)
		end
		gamelogic.standup_clear_seat(seat)
		table_data.standing[rid] = {rid}
	end
	TableLogic.leavetable(table_data, {rid = rid}, isrobot, re)
	if not table_data.gaming and table_data.delete_table_timer_id < 0 then
		if not table_data.conf.match_type then
			TableLogic.startgame(table_data)
		else
			if table_data.playernum >= 2 then
				TableLogic.startgame(table_data)
			end
		end
	end
end

function TableLogic.standuptable(table_data, request, seat)
	if not seat then return end
	if seat.state == ESeatState.SEAT_STATE_COMPARE_FAIL or seat.state == ESeatState.SEAT_STATE_FOLD then
		if table_data.conf.room_type == ERoomType.ROOM_TYPE_DIAMOND
		or table_data.conf.room_type == ERoomType.ROOM_TYPE_COIN
		or table_data.conf.room_type == ERoomType.ROOM_TYPE_ZJ_DIAMOND then
			TableLogic.game_leave_noend(table_data, seat.rid)
		end
	end

	if not TableLogic.is_onegameend(table_data) then
		local action = timetool.get_time() .. "_"
			.. seat.rid .. "_"
			.. '-2' .. "_"
			.. '0' .. "_"
			.. (table_data.all_bets or '0') .. "_"
			.. '0'
		TableLogic.save_actions(table_data, action)

		if gamelogic.is_ingame(seat) == true then
			if seat.state ~= ESeatState.SEAT_STATE_WATCHING
				and seat.state ~= ESeatState.SEAT_STATE_COMPARE_FAIL
				and seat.state ~= ESeatState.SEAT_STATE_FOLD then
				gamelogic.onstanduptable(seat)
			end
			if seat.state ~= ESeatState.SEAT_STATE_WATCHING then
				local losecoin, losediamond = 0, 0
				if table_data.conf.room_type == ERoomType.ROOM_TYPE_DIAMOND or table_data.conf.room_type == ERoomType.ROOM_TYPE_ZJ_DIAMOND then
					losecoin = 0
					losediamond = seat.diamond - seat.diamond_base
				elseif table_data.conf.room_type == ERoomType.ROOM_TYPE_COIN then
					losecoin = table_data.tmpdiamond.coin[seat.rid]
					if table_data.tmpdiamond.diamond and table_data.tmpdiamond.diamond[seat.rid] then
						losediamond = table_data.tmpdiamond.diamond[seat.rid].value
					end
				end

				table_data.leaves = table_data.leaves or {}
				table_data.leaves[seat.index] = {
					rid = seat.rid,
					seat_index = seat.index,
					rolename = seat.playerinfo.rolename,
					logo = seat.playerinfo.logo,
					lose_money = seat.diamond - seat.diamond_base,
					lose_diamond = losediamond,
					lose_coin = losecoin,
					card_type = cardtool.getCardType(seat.cards) or -1,
					cards = tabletool.deepcopy(seat.cards),
				}
			end
		end
	end
	
	table_data.sitdown_player_num = table_data.sitdown_player_num - 1
	table_data.playernum = table_data.playernum - 1
	if table_data.conf.room_type == ERoomType.ROOM_TYPE_DIAMOND then
		local data = {
			cur_player = table_data.sitdown_player_num,
			is_public = table_data.conf.is_public,
			mtype = table_data.conf.match_type,
			rtype = table_data.conf.room_type,
			count = -1,
			rid = seat.rid,
			logo = nil,
		}
		msghelper:sendmsg_to_roomsvr("update_table_player", table_data.conf.idx, data)
	end
	if seat.isrobot then
		msghelper:sendmsg_to_roomsvr("change_robot_num", -1, table_data.conf.idx, table_data.conf.is_public, table_data.conf.match_type, table_data.conf.room_type)
	end

	local noticemsg = {
		rid = seat.rid, 
		seat_index = seat.index,
		state = seat.state,
		reason = EStandupReason.STANDUP_REASON_ONSTANDUP,
	}
	msghelper:sendmsg_to_alltableplayer("standuptableN", noticemsg)
	if seat.index == table_data.winer_index then
		table_data.winer_index = nil
	end
	--初始化座位数据
	gamelogic.standup_clear_seat(seat)
	table_data.standing[seat.rid] = {seat.rid}
	if not table_data.gaming and table_data.delete_table_timer_id < 0 then
		if not table_data.conf.match_type then
			TableLogic.startgame(table_data)
		else
			if table_data.playernum >= 2 then
				TableLogic.startgame(table_data)
			end
		end
	end
end

local function doaction(table_data, request, seat, ex)
	if TableLogic.is_onegameend(table_data) then
		return false
	end
	if request.action_type < EActionType.ACTION_TYPE_SEECARDS then
		if table_data.state ~= ETableState.TABLE_STATE_WAIT_CLIENT_ACTION then return false end
		if seat.index ~= table_data.seat_index then
			return false
		end
		table_data.state = ETableState.TABLE_STATE_ACTION
		if table_data.timer_id and table_data.timer_id > 0 then
			timer.cleartimer(table_data.timer_id)
			table_data.timer_id = -1
		end
	end
	if request.action_type == EActionType.ACTION_TYPE_RAISE then
		table_data.robotdata.raisevalue = request.action_param
	elseif request.action_type == EActionType.ACTION_TYPE_FOLD then
		if table_data.comparing then
			return false
		end
	end
	table_data.action_type = request.action_type
	table_data.action_param = request.action_param
	if gamelogic.actions[request.action_type] then
		return gamelogic.actions[request.action_type](seat, request.action_param, ex)
	else
		filelog.error("action type error!")
		return false
	end
	-------------------------- robot --------------------------
	skynet.fork(function()
		for _, value in ipairs(table_data.seats) do
			if value.state == ESeatState.SEAT_STATE_PLAYING and value.isrobot and value.seecards == 0 then
				if math.random(100) <= 20 * (table_data.robotdata.seecardscount + 1) then
					request.action_type = EActionType.ACTION_TYPE_SEECARDS
					skynet.sleep(math.random(200, 300))
					if table_data.state >= ETableState.TABLE_STATE_GAME_END then return end
					request.rid = value.rid
					TableLogic.doaction(table_data, request, value)
					break
				end
			end
		end
	end)

	-------------------------- robot test --------------------------
	skynet.fork(function()
		for _, value in ipairs(table_data.seats) do
			if value.state == ESeatState.SEAT_STATE_PLAYING and value.istest and value.seecards == 0 then
				if math.random(100) <= 20 * (table_data.robotdata.seecardscount + 1) then
					request.action_type = EActionType.ACTION_TYPE_SEECARDS
					skynet.sleep(math.random(200, 300))
					if table_data.state >= ETableState.TABLE_STATE_GAME_END then return end
					request.rid = value.rid
					TableLogic.doaction(table_data, request, value)
					break
				end
			end
		end
	end)
end

function TableLogic.doaction(table_data, request, seat, ex)
	return cs(doaction, table_data, request, seat, ex)
end

function TableLogic.get_sitdown_player_num(table_data)
	return table_data.sitdown_player_num
end

--根据指定桌位号获得一张空座位
function TableLogic.get_emptyseat_by_index(table_data)
	for index, seat in pairs(table_data.seats) do
		if seatlogic.is_empty(seat) then
			return seat
		end
	end
end

function TableLogic.get_seat_by_rid(table_data, rid)
	for index, seat in pairs(table_data.seats) do
		if rid == seat.rid then
			return seat
		end
	end
end

--判断桌子是否满了
function TableLogic.is_full(table_data)
	return table_data.sitdown_player_num >= table_data.conf.max_player_num
end

--判断当前是否能够开始游戏
function TableLogic.is_canstartgame(table_data)
	local isallready = true
	local realplayer = 0
	for k, v in ipairs(table_data.seats) do
		if v.state ~= ESeatState.SEAT_STATE_NO_PLAYER then
			if v.state ~= ESeatState.SEAT_STATE_WAIT_START then
				isallready = false
				-- break
			end
			realplayer = realplayer + 1
		end
	end
	if realplayer < 1 then isallready = false end
	-- filelog.warn("isallready = ", isallready)
	if isallready then
		if table_data.conf.room_type == ERoomType.ROOM_TYPE_ZJ_FRIEND then
			if table_data.cur_games_times == 0 then
				if table_data.sitdown_player_num >= table_data.conf.min_player_num then
					return table_data.enterclose
				end
				return false
			else
				return table_data.sitdown_player_num >= table_data.conf.min_player_num
			end
		else
			return table_data.sitdown_player_num >= table_data.conf.min_player_num
		end
	else
		return isallready
	end
end

--判断当前局是否已经结束游戏
function TableLogic.is_onegameend(table_data)
	return not table_data.gaming
end

function TableLogic.get_gamename(table_data)
	local gamename = "psz"
    if table_data.conf.room_type == ERoomType.ROOM_TYPE_DIAMOND then
		gamename = gamename .. "_diamond_".. table_data.conf.match_type
	elseif table_data.conf.room_type == ERoomType.ROOM_TYPE_ZJ_DIAMOND then
		gamename = gamename .. "_diamond_".. "zj"
    end
    return gamename
end

--每个玩家随机牌
function TableLogic.randcardlist4seat(table_data)
	local cardBuffer = cardtool.RandCardList(table_data.conf.game_type)
	table_data.gamerecords.initcards = json.encode(cardBuffer)
	local handcards = {}
	for i = 1, table_data.conf.max_player_num do
		local seat = table_data.seats[i]
		if seat.state > ESeatState.SEAT_STATE_NO_PLAYER and seat.state ~= ESeatState.SEAT_STATE_WATCHING then
			for j = 1, g_PerPlaCardCount do
				local cardVal = cardBuffer[(i - 1) * g_PerPlaCardCount + j]

				local cardType = math.ceil(cardVal / g_CardDivisor);
				if (cardType == ColorType.Heart) then
					cardVal = cardVal % g_HeartDivisor
				elseif (cardType == ColorType.Plum) then
					cardVal = cardVal % g_PlumDivisor
				elseif (cardType == ColorType.Block) then
					cardVal = cardVal % g_BlockDivisor
				elseif (cardType ~= ColorType.Spade) then
					cardType = ColorType.Wang
				end

				local cardinfo = {
					card_value = cardVal,
					card_type = cardType,
				}
					
				seat.cards[j] = cardinfo
			end
			-- table.insert(handcards, seat.cards)
			handcards[seat.rid] = seat.cards
		end
		-- filelog.debug("randcardlist4seat " .. tostring(seat.index) .. " ======>>> ", seat.cards)
	end
	table_data.gamerecords.handcards = json.encode(handcards)
	for _, seat in ipairs(table_data.seats) do
		if seat.isrobot and seat.state > ESeatState.SEAT_STATE_NO_PLAYER and seat.state ~= ESeatState.SEAT_STATE_WATCHING then
			local canwinall = true
			for _, compareseat in ipairs(table_data.seats) do
				if seat.index ~= compareseat.index and compareseat.state > ESeatState.SEAT_STATE_NO_PLAYER and compareseat.state ~= ESeatState.SEAT_STATE_WATCHING then
					if not cardtool.isOvercomePrev(seat.cards, compareseat.cards) then
						canwinall = false
					end
				end 
			end
			-- filelog.warn("seat canwinall = ", canwinall)
			seat.canwinall = canwinall
		end
	end
end

local function caclate_tip(base)
	-- if base <= 10 then
	-- 	return base
	-- else
		return math_ceil(base*0.5)
	-- end
end

local function caclate_cointip(base)
	-- return math_ceil(base*0.2)
	return 10
end

function TableLogic.get_tip(table_data)
    local nodeconf = getnodeconf()
    local tipconf = nodeconf.tipconf
    if not tipconf or not tipconf[table_data.conf.room_type]
    or not tipconf[table_data.conf.room_type][table_data.conf.game_type] then
        local base_cost = table_data.conf.base_score
	    if table_data.conf.room_type == ERoomType.ROOM_TYPE_DIAMOND or table_data.conf.room_type == ERoomType.ROOM_TYPE_ZJ_DIAMOND then
            return caclate_tip(base_cost)
        elseif table_data.conf.room_type == ERoomType.ROOM_TYPE_COIN then
            return caclate_cointip(base_cost)
        end 
    end

	local tip_percent = tipconf[table_data.conf.room_type][table_data.conf.game_type]
	if tip_percent and tonumber(tip_percent) then
        tip_percent = tonumber(tip_percent)
		-- if table_data.conf.base_score <= 10 then
		-- 	return table_data.conf.base_score
		-- else
			return math.floor(table_data.conf.base_score * tip_percent)
		-- end
	end

    return 0
end

function TableLogic.pay_tip(table_data)
	local base_cost = table_data.conf.base_score
	local data = {}	
    local tip = TableLogic.get_tip(table_data)
	
	tip = tip >= 0 and tip or 0
	table_data.tip = tip
	for _, seat in ipairs(table_data.seats) do
		if seat.state == ESeatState.SEAT_STATE_PLAYING then
			data[seat.rid] = {
				beginvalue = seat.getdiamond,
				value = tip,
				endvalue = 0,
			}
			seat.diamond = seat.diamond - tip
			seat.getdiamond = seat.getdiamond - tip
			if table_data.conf.room_type == ERoomType.ROOM_TYPE_DIAMOND or table_data.conf.room_type == ERoomType.ROOM_TYPE_ZJ_DIAMOND then
				seat.playerinfo.diamond = seat.diamond
			elseif table_data.conf.room_type == ERoomType.ROOM_TYPE_COIN then
				seat.playerinfo.coin = seat.diamond
			end
			seat.diamond_base = seat.diamond_base - tip
			data[seat.rid].endvalue = seat.getdiamond
		end
	end
	local commnet = {
		table_uuid = table_data.gamerecords.table_uuid,		
		table_tradeid = skynet.call(".nodeuuid", "lua", "getuuid"),
		start_time = table_data.gamerecords.start_time,
	}
	if table_data.conf.room_type == ERoomType.ROOM_TYPE_DIAMOND or table_data.conf.room_type == ERoomType.ROOM_TYPE_ZJ_DIAMOND then
		if not msghelper:callmsg_to_gatesvr("game_sub_fuwufei", data, commnet) then
			filelog.sys_error("pay_tip serious error: ", data, commnet)
		end
	elseif table_data.conf.room_type == ERoomType.ROOM_TYPE_COIN then
		msghelper:sendmsg_to_gatesvr("game_sub_coin", data, commnet)
	end
	table_data.gamerecords.tip = tip
	-- msghelper:sendmsg_to_alltableplayer("paytipN", {
	-- 	tip = tip,
	-- })
end

-- 系统收费
function TableLogic.pay_tip_ex(table_data, winseat)
	local commnet = {
		table_uuid = table_data.gamerecords.table_uuid,		
		table_tradeid = skynet.call(".nodeuuid", "lua", "getuuid"),
		start_time = table_data.gamerecords.start_time,
	}
	if table_data.conf.room_type == ERoomType.ROOM_TYPE_DIAMOND or table_data.conf.room_type == ERoomType.ROOM_TYPE_ZJ_DIAMOND then
		msghelper:sendmsg_to_gatesvr("game_sub_diamond", table_data.tmpdiamond[winseat.rid], commnet)
	end
end

function TableLogic.change_money(table_data, seat, changevalue)
	if not seat then return end
	if table_data.conf.room_type == ERoomType.ROOM_TYPE_DIAMOND or table_data.conf.room_type == ERoomType.ROOM_TYPE_ZJ_DIAMOND then
		if seat.diamond + changevalue >= 0 then
			seat.diamond = seat.diamond + changevalue
			seat.playerinfo.diamond = seat.playerinfo.diamond + changevalue
		else
			seat.diamond = 0
			seat.playerinfo.diamond = 0
			filelog.sys_error("TableLogic change money error", seat.rid, seat.diamond, changevalue)
		end
	elseif table_data.conf.room_type == ERoomType.ROOM_TYPE_COIN then
		if seat.diamond + seat.playerinfo.diamond + changevalue >= 0 then
			seat.diamond = seat.diamond + changevalue
			seat.playerinfo.coin = seat.playerinfo.coin + changevalue
			if seat.diamond + changevalue < 0 then
				seat.playerinfo.diamond = seat.playerinfo.diamond + (seat.diamond + changevalue)
			end
		else
			seat.diamond = 0
			seat.playerinfo.coin = 0
			filelog.sys_error("TableLogic change money error", seat.rid, seat.diamond, changevalue)
		end
	elseif table_data.conf.room_type == ERoomType.ROOM_TYPE_ZJ_FRIEND then
		seat.diamond = seat.diamond + changevalue
	end
end

function TableLogic.save_actions(table_data, action)
	local records = table_data.gamerecords
	if type(records) ~= type{} or not records.logname then
		filelog.sys_error("save actions error: no records")
		return
	end
	local logstr = ''
	if not action then
		logstr = logstr
			.. (records.table_uuid or '0') .. '\n'
			.. table_data.conf.room_type .. '\n'
			.. (records.tip or '0') .. '\n'
			.. (records.conf or "{}") .. '\n'
			.. (records.start_time or '0') .. '\n'
			.. (records.playerdata or '{}') .. '\n'
			.. (records.initcards or "{}") .. '\n'				-- 初始牌堆
			.. (records.handcards or "{}")
	else
		logstr = logstr .. action
	end
	-- filelog.info("logstr = ", logstr)
	skynet.call(".tablereplaylog", "lua", "write", records.logname, logstr)
end

local function save_gamerecords(table_data, commnet)
	local records = table_data.gamerecords
	if type(records) ~= type{} or not records.logname then
		filelog.sys_error("save game records error: no records")
		return
	end
	
	local diamondinfo = {}
	local balanceinfo = {}
	local rids = ''
	for rid, data in pairs(table_data.tmpdiamond) do
		table.insert(diamondinfo, {
			rid = rid,
			rolename = data.rolename,
			value = data.value,
		})
		balanceinfo[rid] = {
			winvalue = data.value,
			gamestar_diamond = data.beginvalue,
			gameend_diamond = data.endvalue,
		}
		if rids == '' then
			rids = rids .. rid
		else
			rids = rids .. '_' .. rid
		end
	end

	local ts = timetool.get_time()
	local logname = '' .. records.table_uuid .. '_'
		.. records.start_time .. '_' .. ts .. '_'
		.. (records.rids or rids) .. '_' .. os.date("%Y%m%d_%H%M%S", records.start_time or 0) .. '_'
		.. table_data.conf.game_room_type
	-- filelog.debug("logname = ", logname)

	local logstr = ''
		.. (records.table_uuid or '0') .. '\n'
		.. table_data.conf.room_type .. '\n'
		.. (records.tip or '0') .. '\n'
		.. (records.conf or "{}") .. '\n'
		.. (records.start_time or '0') .. '\n'
		.. ts .. '\n'
		.. json.encode(balanceinfo) .. '\n'
		.. commnet.table_tradeid .. '\n'
		.. json.encode(diamondinfo) .. '\n'
		.. json.encode({}) .. '\n'				-- 结算算番情况
		.. (records.initcards or "{}") .. '\n'	-- 初始牌堆

	-- filelog.debug("logstr = ", logstr)
	skynet.call(".tablerecordlog", "lua", "write", logname, logstr, records.handcards or "{}")
end

function TableLogic.pay_roomcard(table_data)
	local data = {}
	for _, seat in ipairs(table_data.seats) do
		if seat.state ~= ESeatState.SEAT_STATE_NO_PLAYER then
			seat.playerinfo.fangka = seat.playerinfo.fangka - seat.fangka
			data[seat.rid] = {
				value = seat.fangka*100,
			}
		end
	end
	local commnet = {
		table_uuid = skynet.getenv("nodename") .. "_" .. table_data.conf.table_code .. "_" .. table_data.conf.idx .. "_" .. timetool.get_time(),		
		table_tradeid = skynet.call(".nodeuuid", "lua", "getuuid"),	
	}
	msghelper:sendmsg_to_gatesvr("game_sub_fangka", data, commnet)
end

function TableLogic.change_all_player_money(table_data)
	if not table_data.tmpdiamond then
		filelog.sys_error("no data for changing player money,is somewhere error???")
		return
	end

	local records = table_data.gamerecords
	if type(records) ~= type{} or not records.logname then
		filelog.sys_error("change all player money error: no records")
		return
	end

	local comment = {
		table_uuid = records.table_uuid,
		table_tradeid = skynet.call(".nodeuuid", "lua", "getuuid"),
		start_time = records.start_time or '0',
		replay_logname = records.logname,
	}

	if table_data.conf.room_type == ERoomType.ROOM_TYPE_DIAMOND or table_data.conf.room_type == ERoomType.ROOM_TYPE_ZJ_DIAMOND then
		comment.is_matchtable = table_data.conf.match_type and true or false
		if not msghelper:callmsg_to_gatesvr("game_balance_diamond", table_data.tmpdiamond, comment) then
			filelog.sys_error("change_all_player_money serious error: ", table_data.tmpdiamond, comment)
			-- 严重错误，数据回滚
			for _, seat in ipairs(table_data.seats) do
				if seat.state ~= ESeatState.SEAT_STATE_NO_PLAYER then
					seat.diamond = seat.diamond_base
					seat.getdiamond = seat.diamond
					seat.playerinfo.diamond = seat.diamond
				end
			end
		end
		local total_change, total_water, total_bet, total_income = 0, 0, 0, 0
		for rid, item in pairs(table_data.tmpdiamond) do
			local seat = TableLogic.get_seat_by_rid(table_data, rid)
			if seat and seat.istest then item.level = 0 end
			if item.level ~= 99 then
				total_change = total_change + item.value
				total_water = total_water + math.abs(item.real_change or 0)

				--记录下注值
            	local bet_logstr = string.format("%d,%d,%d,%d,%d,%d,%d,%d,%d,%s,%s,%s", EDiamondChange.DOBET, rid, item.level, 
            	0, 0, 0, 0, 0, 0, comment.table_uuid, comment.start_time, comment.table_tradeid)
            	skynet.send(".diamondlog", "lua", "write", bet_logstr)
                --记录流水变化值
            	local chg_logstr = string.format("%d,%d,%d,%d,%d,%d,%d,%d,%d,%s,%s,%s", EDiamondChange.FUWUFEI, rid, item.level, item.real_change, 
            	item.beginvalue, item.endvalue, 0, 0, 0, comment.table_uuid, comment.start_time, comment.table_tradeid)
            	if item.real_change ~= 0 then
                	skynet.send(".diamondlog", "lua", "write_file_redis", chg_logstr, rid)
            	else
                	skynet.send(".diamondlog", "lua", "write", chg_logstr)
				end
			else
				if item.value ~= 0 then
					total_income = total_income + item.value
				end
			end
		end
		if total_income ~= 0 then
			skynet.send(".slotmgr", "lua", "update_sys_income", TableLogic.get_gamename(table_data), total_income, comment)
		end
		skynet.send(".slotmgr", "lua", "handle_balance_result", 
			TableLogic.get_gamename(table_data), total_change, total_water, total_bet, comment, table_data.conf.base_score)
	elseif table_data.conf.room_type == ERoomType.ROOM_TYPE_COIN then
		msghelper:sendmsg_to_gatesvr("game_balance_coin_diamond", table_data.tmpdiamond, comment)
	end
	-- filelog.trace("change all player money: ", table_data.tmpdiamond, comment)
	-- save_gamerecords(table_data, comment)
end

function TableLogic.save_tablerecord(table_data, record)
	if not record then
		filelog.sys_error("no data for save_table_record,is somewhere error???")
		return
	end

	local records = table_data.gamerecords
	if type(records) ~= type{} or not records.logname then
		filelog.sys_error("save_table_record error: no records")
		return
	end

	local commnet = {
		table_uuid = records.table_uuid,
		table_tradeid = skynet.call(".nodeuuid", "lua", "getuuid"),
		start_time = records.start_time or '0',
	}
	-- filelog.debug("save_table_record:", record, commnet)
	msghelper:sendmsg_to_gatesvr("game_balance_fangka", record, commnet)
end

function TableLogic.game_leave_noend(table_data, rid)
	if table_data.balanced then return end

	if table_data.conf.room_type == ERoomType.ROOM_TYPE_DIAMOND or table_data.conf.room_type == ERoomType.ROOM_TYPE_ZJ_DIAMOND then
		if not table_data.tmpdiamond or not table_data.tmpdiamond[rid] then
			filelog.sys_error("no data for game_leave_noend,is somewhere error???")
			return
		end
	elseif table_data.conf.room_type == ERoomType.ROOM_TYPE_COIN then
		if not table_data.tmpdiamond or not table_data.tmpdiamond.coin or not table_data.tmpdiamond.coin[rid] then
			filelog.sys_error("no data for game_leave_noend,is somewhere error???")
			return
		end
	end

	local records = table_data.gamerecords
	if type(records) ~= type{} or not records.logname then
		filelog.sys_error("game_leave_noend error: no records")
		return
	end

	local commnet = {
		table_uuid = records.table_uuid,
		table_tradeid = skynet.call(".nodeuuid", "lua", "getuuid"),	
		start_time = records.start_time or '0',
	}
	if table_data.conf.room_type == ERoomType.ROOM_TYPE_DIAMOND or table_data.conf.room_type == ERoomType.ROOM_TYPE_ZJ_DIAMOND then
		local tmpdiamond = {[rid] = tabletool.deepcopy(table_data.tmpdiamond[rid])}
		if not msghelper:callmsg_to_gatesvr("game_half_diamond", tmpdiamond, commnet) then
			filelog.sys_error("game_leave_noend serious error: ", tmpdiamond, commnet)
			return
		end
		table_data.tmpdiamond[rid].had_half = true
	elseif table_data.conf.room_type == ERoomType.ROOM_TYPE_COIN then
		local tmpdiamond = {coin = {}}
		tmpdiamond.coin[rid] = table_data.tmpdiamond.coin[rid]
		table_data.tmpdiamond.coin[rid].had_half = true
		if table_data.tmpdiamond.diamond and table_data.tmpdiamond.diamond[rid] then
			tmpdiamond.diamond = {}
			tmpdiamond.diamond[rid] = table_data.tmpdiamond.diamond[rid]
			table_data.tmpdiamond.diamond[rid].had_half = true
		end
		msghelper:sendmsg_to_gatesvr("game_half_coin_diamond", tmpdiamond, commnet)
	end
	return true
end

--- 保存牌桌每局战绩记录
-- @param table_data 桌子对象
function TableLogic.saveOneGamerecords(table_data, data)
	for _, seat in ipairs(table_data.seats) do
		local tablerecords = {}
		tablerecords.game_type = 2
		tablerecords.index_id = ""..tostring(table_data.idx)..tostring(table_data.conf.create_user_rid)..tostring(seat.rid)..tostring(timetool.get_time())
		tablerecords.table_id = table_data.idx
		tablerecords.table_create_time = table_data.conf.create_time
		tablerecords.table_create_rid = table_data.conf.create_user_rid
		tablerecords.table_base_coin = table_data.conf.base_score
		tablerecords.table_max_coin = table_data.conf.max_score
		tablerecords.rid = seat.rid
		tablerecords.record = tabletool.deepcopy(data)
		msghelper:sendmsg_to_datasvr("save_onegame_record", seat.rid, tablerecords)
	end
end

function TableLogic.get_jacktip(table_data)
    local room_type = table_data.conf.room_type
    local game_type = table_data.conf.game_type
	local base_cost = table_data.conf.base_score
	if base_cost <= 10 then return 0 end
    local nodeconf = getnodeconf()
    local jackoptconf = nodeconf.jackoptconf
	if not jackoptconf or not jackoptconf.chargeconf 
    or not jackoptconf.chargeconf[room_type]
    or not jackoptconf.chargeconf[room_type][game_type] then 
        return 0
    end

    local jackpoint = jackoptconf.chargeconf[room_type][game_type]
    return math.floor( base_cost * jackpoint)
end

---扣除奖池抽水
function TableLogic.pay_jackopt(table_data)
	if table_data.conf.base_score <= 10 then return end
    local data = {}
	
	local jacktip = TableLogic.get_jacktip(table_data)
    jacktip = (jacktip >= 0 and jacktip) or 0
	table_data.jacktip = jacktip

    local jacktips = {}
	for _, seat in ipairs(table_data.seats) do
		if seat.state == ESeatState.SEAT_STATE_PLAYING then
			data[seat.rid] = {
				beginvalue = seat.getdiamond,
				value = jacktip,
				endvalue = 0,
			}
			seat.diamond = seat.diamond - jacktip
			seat.getdiamond = seat.getdiamond - jacktip
			seat.diamond_base = seat.diamond_base - jacktip
			data[seat.rid].endvalue = seat.getdiamond

            local jacktipsobj = { 
                rid = seat.rid, 
                jacktip = jacktip, 
                money_type = EMoneyType.DIAMOND, 
			    beginvalue = data[seat.rid].beginvalue, 
			    endvalue = data[seat.rid].endvalue
			}
            if table_data.conf.room_type == ERoomType.ROOM_TYPE_DIAMOND or table_data.conf.room_type == ERoomType.ROOM_TYPE_ZJ_DIAMOND then
				seat.playerinfo.diamond = seat.diamond
			elseif table_data.conf.room_type == ERoomType.ROOM_TYPE_COIN then
				seat.playerinfo.coin = seat.diamond
                jacktipsobj.money_type = EMoneyType.COIN
			end
            table.insert(jacktips, jacktipsobj)
		end
	end
	local commnet = {
		table_uuid = table_data.gamerecords.table_uuid,		
		table_tradeid = skynet.call(".nodeuuid", "lua", "getuuid"),
		start_time = table_data.gamerecords.start_time,
	}
	if table_data.conf.room_type == ERoomType.ROOM_TYPE_DIAMOND then
		if not msghelper:callmsg_to_gatesvr("jackpot_sub_diamond", data, commnet) then
			filelog.sys_error("pay_jacktip serious error: ", data, commnet)
		end
	elseif table_data.conf.room_type == ERoomType.ROOM_TYPE_COIN then
		msghelper:sendmsg_to_gatesvr("jackpot_sub_coin", data, commnet)
	end
	table_data.gamerecords.jacktip = jacktip

	---更新奖池货币到总奖池
	skynet.send(".jackpotmgr", "lua", "updatejackoptnum", jacktips, commnet)
end

----获得奖池信息到牌桌
function TableLogic.get_jackoptinfo(table_data)
	local result = skynet.call(".jackpotmgr", "lua", "getjackInfo", table_data.conf.base_score)
	if next(result) ~= nil then
		if result.jackopt_num and result.money_type then
			if table_data.jackopt_info == nil then table_data.jackopt_info = {} end
			table_data.jackopt_info.jackopt_num = result.jackopt_num
			table_data.jackopt_info.money_type = result.money_type
		end
	end
end

---向奖池服务注册牌桌,奖池变化和分配时通知牌桌
function TableLogic.register_jackopt(table_data)
	skynet.send(".jackpotmgr", "lua", "register_table", table_data.conf.base_score, table_data.conf.table_code, skynet.self())
end

---从奖池服务里注销牌桌
function TableLogic.unregister_jackopt(table_data)
	skynet.send(".jackpotmgr", "lua", "unregister_table", table_data.conf.base_score, table_data.conf.table_code)
end

function TableLogic.get_horseracelamp(rolename, card_type, get_num, moneyname, cards)
	local horseconf = configdao.get_common_conf("horselampconf")
	if not horseconf or not horseconf[1] then return end
	local formatname = string.format(PSZLAMPCOLOR.GREEN, rolename)
	local formatnum = string.format(PSZLAMPCOLOR.RED, tostring(get_num / 100))
    local formatmoney = string.format(PSZLAMPCOLOR.RED, moneyname)
    local cardtypename = PSZCardTypeName[card_type]
    if card_type >= CardType.BAO_ZI then
        local card_value = cards[1].card_value
        local cv_names = {[11] = "J", [12] = "Q", [13] = "K", [14] = "A"}
        cardtypename = cardtypename .. (cv_names[card_value] or tostring(card_value))
    end
    local formatcardtype = string.format(PSZLAMPCOLOR.GOLD,cardtypename)
	local horsestring = string.format(horseconf[1], formatname, EGameName, formatcardtype, formatnum, formatmoney)
	local msg = {
		content = horsestring,
	}
	return msg
end

function TableLogic.send_horseracelamp(msg)
	msghelper:sendmsg_to_gatesvr("addpopmessage", msg)
end

--检测是否触发奖池
--豹子，同花顺触发
--
function TableLogic.check_cangetjack(card_type)
	local canget = false
    local nodeconf = getnodeconf()
	local jackoptconf = nodeconf.jackoptconf
	if not jackoptconf or not jackoptconf.getjackopt then
        return canget 
    end

	for cardtype, get_per in pairs(jackoptconf.getjackopt) do
		if tonumber(cardtype) == card_type then
            return true
        end
	end
	return canget
end

--处理开奖
function TableLogic.handle_openjackpot(table_data, getjackplayers)
    if not getjackplayers or #getjackplayers < 1 then
        return
    end

    local moneyname = "金豆"
    if table_data.conf.room_type == ERoomType.ROOM_TYPE_COIN then
        moneyname = "金币"
    end

    local data = {}
    local commnet = {
	    table_uuid = table_data.gamerecords.table_uuid,		
	    table_tradeid = skynet.call(".nodeuuid", "lua", "getuuid"),
	    start_time = table_data.gamerecords.start_time,
    }
	local jackplayers = skynet.call(".jackpotmgr", "lua", "openjackopt", getjackplayers, table_data.conf.table_code, commnet)
	if jackplayers and next(jackplayers) ~= nil then
		for index, jackplayer in ipairs(jackplayers) do
            local changevalue = jackplayer.getoptnum
            local seat = TableLogic.get_seat_by_rid(table_data, jackplayer.rid)
		    data[seat.rid] = {
			    beginvalue = seat.getdiamond,
			    value = changevalue,
			    endvalue = 0,
                rolename = seat.playerinfo.rolename,
		    }
		    seat.diamond = seat.diamond + changevalue
		    seat.getdiamond = seat.getdiamond + changevalue
		    if jackplayer.money_type == EMoneyType.DIAMOND then
			    seat.playerinfo.diamond = seat.diamond
		    elseif jackplayer.money_type == EMoneyType.COIN then
			    seat.playerinfo.coin = seat.diamond
		    end
		    seat.diamond_base = seat.diamond_base + changevalue
		    data[seat.rid].endvalue = seat.getdiamond
            --通知客户端
            local noticemsg = {
			    rid = seat.rid,
			    card_type = jackplayer.card_type,
			    getjackopt_num = jackplayer.getoptnum,
		    }
            msghelper:sendmsg_to_tableplayer(seat, "getjackoptN", noticemsg)
            local msg = TableLogic.get_horseracelamp(seat.playerinfo.rolename, jackplayer.card_type, jackplayer.getoptnum, moneyname, seat.cards)
            table.insert(table_data.horseracelamps,msg)
        end

        if table_data.conf.room_type == ERoomType.ROOM_TYPE_DIAMOND then
	        msghelper:callmsg_to_gatesvr("open_jackpot_diamond", "psz", data, commnet)
        elseif table_data.conf.room_type == ERoomType.ROOM_TYPE_COIN then
	        msghelper:sendmsg_to_gatesvr("open_jackpot_coin", "psz", data, commnet)
        end
	end
end

--保存牌型记录
function TableLogic.save_cardtype_record(gamemode, card_types, playernum)
    local record_list = nil
    local result, data = redisdao.query_data(".gmmqredis", "hget", "psz_cardtype_record", gamemode)
    if result and data then
        record_list = json.decode(data)
    end

    record_list = record_list or {}
    if card_types then
        for _,card_type in pairs(card_types) do
            record_list[tostring(card_type)] = (record_list[tostring(card_type)] or 0) + 1
        end
    end
    if playernum then
        record_list.total_count = (record_list.total_count or 0) + playernum
    end
    redisdao.query_data(".gmmqredis", "hset", "psz_cardtype_record", gamemode, json.encode(record_list))
end

return TableLogic
